<html lang="en">

<head>
    <meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no">
    <title>WebWhiz Live Chat</title>
    <base target="_parent">
    <link rel="stylesheet" href="app.css">
</head>

<body>
    <!--A chatbot markup with a launcher to open and close vhat widget-->
    <div class="board-wrap board-wrap-ai-assistant" id="board-wrap" style="opacity: 0">

        <div class="board-launcher" id="board-launcher">
            <button class="board-launcher-btn" id="board-launcher-btn">
            </button>
        </div>
        <div class="chat-widget">
            <div class="chat-header">
                <div class="chat-header-top">
                    <div class="chat-tabs" id="chat-tabs">
                        <button id="tab-ai-assistant">AI assistant</button>
                        <button id="tab-offline-msg">Offline message</button>
                        <div class="tabs-active" id="tabs-active"></div>
                    </div>
                    <div class="board-action" id="board-action">
                        <button class="board-min-btn board-action-btn" id="board-min-btn">
                            <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24"
                                stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em"
                                xmlns="http://www.w3.org/2000/svg" style="
                                width: 22px;
                                height: 22px;
                            ">
                                <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
                                <path
                                    d="M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z">
                                </path>
                                <path d="M9 4v16"></path>
                                <path d="M14 10l2 2l-2 2"></path>
                            </svg>
                        </button>
                        <button class="board-max-btn board-action-btn" id="board-max-btn">
                            <svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24"
                                stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em"
                                xmlns="http://www.w3.org/2000/svg" style="
                        width: 22px;
                        height: 22px;
                    ">
                                <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
                                <path
                                    d="M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z">
                                </path>
                                <path d="M15 4v16"></path>
                                <path d="M10 10l-2 2l2 2"></path>
                            </svg>
                        </button>
                        <button title="Clear chat history" class="board-clear-sess-btn board-action-btn"
                            id="board-clear-sess-btn">
                            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24"
                                fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                                stroke-linejoin="round" class="feather feather-refresh-ccw">
                                <polyline points="1 4 1 10 7 10"></polyline>
                                <polyline points="23 20 23 14 17 14"></polyline>
                                <path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"></path>
                            </svg>
                        </button>
                        <button class="board-close-btn board-action-btn" id="board-close-btn">
                            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
                                fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
                                stroke-linejoin="round" class="feather feather-x">
                                <line x1="18" y1="6" x2="6" y2="18"></line>
                                <line x1="6" y1="6" x2="18" y2="18"></line>
                            </svg>
                        </button>
                    </div>
                </div>

                <div class="ai-assistant-header">
                    <h2 id="board-heading">
                        I'm your AI assistant
                    </h2>
                    <p id="board-desc">Ask me anything. I can answer same like chatGPT but with the data from this
                        website</p>
                </div>
                <div class="offline-msg-header">
                    <h2 id="offline-msg-heading">
                        Offline message
                    </h2>
                    <p id="offline-msg-desc">Please fill out the form below and we will get back to you as
                        soon as possible.</p>
                </div>

            </div>
            <div id="board-msg" class="board-msg">
            </div>
            <div id="offline-msg" class="offline-msg">
                <div class="form-group">
                    <label for="offline-msg-name"><span id="label-offline-msg-name">Name</span> <span class="form-required">*</span></label>
                    <input type="text" class="form-control" id="offline-msg-name" placeholder="Enter your name">
                    <!--Error message-->
                    <div class="invalid-feedback required-field" id="invalid-feedback-name">This field is required</div>

                </div>
                <div class="form-group">
                    <label for="offline-msg-email"><span id="label-offline-msg-email">Email</span> <span class="form-required">*</span></label>
                    <input type="text" class="form-control" id="offline-msg-email" placeholder="Enter your email">
                    <!--Error message-->
                    <div class="invalid-feedback required-field" id="invalid-feedback-email">This field is required</div>
                    <div class="invalid-feedback" id="invalid-feedback-email-invalid">Please enter a valid email</div>

                </div>
                <div class="form-group">
                    <label for="offline-msg-msg"><span id="label-offline-msg-msg">Message</span> <span class="form-required">*</span></label>
                    <textarea class="form-control" rows="4" id="offline-msg-msg"
                        placeholder="Enter your message"></textarea>
                    <!--Error message-->
                    <div class="invalid-feedback required-field" id="invalid-feedback-message">This field is required</div>

                </div>
                <button class="btn btn-primary" loadingText="Submitting..." id="offline-msg-submit"
                    type="button">Submit</button>
                <div class="message-feedback message-feedback-success" id="message-success">
                    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path
                            d="M9 11L11 13L15.5 8.5M11.9932 5.13581C9.9938 2.7984 6.65975 2.16964 4.15469 4.31001C1.64964 6.45038 1.29697 10.029 3.2642 12.5604C4.75009 14.4724 8.97129 18.311 10.948 20.0749C11.3114 20.3991 11.4931 20.5613 11.7058 20.6251C11.8905 20.6805 12.0958 20.6805 12.2805 20.6251C12.4932 20.5613 12.6749 20.3991 13.0383 20.0749C15.015 18.311 19.2362 14.4724 20.7221 12.5604C22.6893 10.029 22.3797 6.42787 19.8316 4.31001C17.2835 2.19216 13.9925 2.7984 11.9932 5.13581Z"
                            stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        </path>
                    </svg>

                    <span id="msg-success-text">Your message sent successfully!</span>

                    <button class="btn btn-primary" id="offline-msg-success-close" type="button">Send Again</button>
                </div>
                <div class="message-feedback message-feedback-error" id="message-error">
                    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path
                            d="M16 16C16 16 14.5 14 12 14C9.5 14 8 16 8 16M17 9.24C16.605 9.725 16.065 10 15.5 10C14.935 10 14.41 9.725 14 9.24M10 9.24C9.605 9.725 9.065 10 8.5 10C7.935 10 7.41 9.725 7 9.24M22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12Z"
                            stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
                    </svg>

                    <span id="msg-error-text">Oops! Something went wrong</span>

                    <button class="btn btn-primary" id="offline-msg-error-close" type="button">Try Again</button>
                </div>
            </div>
            <div class="board-sample-msg hide-sample-msg" id="board-sample-msg">
            </div>
            <form id="board-form" class="board-input-wrap">
                <textarea rows='1' class="board-input textarea js-auto-size" id="board-input"
                    placeholder="Type your message"></textarea>
                <button class="chat-submit-btn" type="submit"><svg width="16" height="16" fill="none"
                        xmlns="http://www.w3.org/2000/svg">
                        <path fill-rule="evenodd" clip-rule="evenodd"
                            d="M4.394 14.7L13.75 9.3c1-.577 1-2.02 0-2.598L4.394 1.299a1.5 1.5 0 00-2.25 1.3v3.438l4.059 1.088c.494.132.494.833 0 .966l-4.06 1.087v4.224a1.5 1.5 0 002.25 1.299z"
                            fill="currentColor"></path>
                    </svg></button>
            </form>
            <a id="powered-by" class="powered-by" href="https://www.chatinai.com/" target="_blank">powered by
                chatinai.com</a>
        </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/autosize.js/3.0.20/autosize.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.2.12/marked.min.js"></script>
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>



    <script>
        // const STREAM_RESPONSE = true;
        const STREAM_RESPONSE = false;

        let origin = '';
        let container = '';

        let showReadMore = true;
        let readMoreText = 'Read More:';

        let isFirstMessage = true;

        let collectEmail = false;
        let collectEmailText = 'Read More:';

        const defaultWelcomeMessage = 'Hello! How can I assist you today?';
        const submitBtnSubmittingText = 'Submitting...';

        let sessionId = '';

        let messages = [];

        function getDomainFromUrl(url) {
            if (!url) return '';
            const matches = url.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
            const domain = matches && matches[1]; // domain will be null if no match is found
            return (domain || '').replace('www.', '');
        }

        const urlParams = new URLSearchParams(window.location.search);

        let knowledgebaseId;
        //TODO: 1.修改
        const baseURL = urlParams.get('baseUrl') || 'https://www.chatinai.com';
        const chatWidget = document.querySelector('.board-wrap');

        if(urlParams.get('embed') === 'true') {
            chatWidget.classList.add('widget-open');
        }
        if(urlParams.get('hide-board-action') === 'true') {
            chatWidget.classList.add('hide-board-action');
        }

        /**
         * Iframe communications
         */
        // Msg listener
        window.onmessage = function (event) {
            if (event.data.messageType === 'webwhiz:recieve_meta_data') {
                origin = event.data.url;
                container = event.data.container;

                if (container) {
                    const $chatLauncher = document.getElementById('board-launcher');
                    const $chatActions = document.getElementById('board-action');
                    $chatLauncher.parentNode.removeChild($chatLauncher);
                    $chatActions.parentNode.removeChild($chatActions);
                    chatWidget.classList.add('widget-open');

                    notifyParentWidgetExpand();
                    setTimeout(() => {
                        document.getElementById('board-input').focus();
                    }, 320);
                }
            } else if (event.data.messageType === 'webwhiz:recieve_chat_data') {
                messages = event.data.chatHistory;
                if(messages.length > 0) {
                    isFirstMessage = false;
                }
                let msgHTML = messages.map(msg => {
                    const type = msg.role === 'user' ? 'user' : 'chatbot';
                    let msgContent = msg.content;
                    msgContent = replaceAll(msgContent, '&lt;', '<')
                    msgContent = replaceAll(msgContent, '&gt;', '>')
                    msgContent = replaceAll(msgContent, '<br/>', '\n')
                    const markdownRes = marked.parse(msgContent);
                    return `<div class="chat-msg ${type}"><div class="chat-msg-text">${markdownRes}</div></div>`
                })
                msgHTML = msgHTML.join('');

                const chatMessages = document.getElementById('board-msg');
                chatMessages.insertAdjacentHTML("beforeend", msgHTML)

                chatMessages.scrollTop = chatMessages.scrollHeight;
            } else if (event.data.messageType === 'webwhiz:recieve_session_id') {
                sessionId = event.data.sessionId;
            }
        }

        requestChatHistoryData();
        requestSessionId();

        // {"backgroundColor":"#000","fontColor":"#FFF","borderRadius":"12px","placement":"right"}
        const defaultWidgetData = {
            backgroundColor: "#000",
            fontColor: "#FFF",
            borderRadius: "12px",
            placement: "right"
        }

        const validateEmail = (email) => {
            return String(email)
                .toLowerCase()
                .match(
                    /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
                );
        };

        marked.setOptions({
            highlight: function (code, lang) {
                const language = hljs.getLanguage(lang) ? lang : 'plaintext';
                const hl = hljs.highlight(code, { language: 'javascript' }).value;
                return hl;
            },
            langPrefix: 'hljs language-', // highlight.js css expects a top-level 'hljs' class.
        });

        function escapeRegExp(string) {
            return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
        }
        function replaceAll(str, find, replace) {
            return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
        }


        autosize(document.querySelector('#board-input'));

        // toggle class on chat widget on board-launcher-btn
        const chatLauncherBtn = document.querySelector('.board-launcher-btn');
        const chatCloseBtn = document.querySelector('#board-close-btn');
        const chatMaximizeBtn = document.querySelector('#board-max-btn');
        const chatMinimizeBtn = document.querySelector('#board-min-btn');
        const chatClearHistoryBtn = document.querySelector('#board-clear-sess-btn');
        chatLauncherBtn.addEventListener('click', () => {
            expandWidget();
        });
        chatCloseBtn.addEventListener('click', () => {
            chatWidget.classList.remove('widget-open');
            chatWidget.classList.remove('widget-maximize');
            notifyParentWidgetCollapse();
        });
        chatMaximizeBtn.addEventListener('click', () => {
            chatWidget.classList.toggle('widget-maximize');
            notifyParentWidgetMaximize();
        });
        chatMinimizeBtn.addEventListener('click', () => {
            chatWidget.classList.toggle('widget-maximize');
            notifyParentWidgetMinimize();
        });
        chatClearHistoryBtn.addEventListener('click', () => {
            const chatMessages = document.getElementById('board-msg');
            chatMessages.innerHTML = '';
            sessionId = '';
            messages = [];
            notifyClearHistory();
        });

        function expandWidget() {
            chatWidget.classList.add('widget-open');

            notifyParentWidgetExpand();
            setTimeout(() => {
                const chatMessages = document.getElementById('board-msg');
                chatMessages.scrollTop = chatMessages.scrollHeight;
                document.getElementById('board-input').focus();
            }, 320);
        }

        async function getWidgetData() {
            //const domain = 'chat.timemaster.ai';
            let url;
            //TODO:kbID
            const kbId = urlParams.get('kbId');
            if(kbId) {
                knowledgebaseId = kbId;
                url = `${baseURL}/knowledgebase/${knowledgebaseId}/chat_widget_data`;
            } else {
                //TODO: 根据用户url获取 knowledge base id
                const domain = getDomainFromUrl(window.location.href);
                url = `${baseURL}/knowledgebase/chat_widget_data_for_domain?domain=${domain}`;
                chatWidget.classList.add('hide-board-action', 'widget-open');
            }



            // const response = await fetch(
            //     url,
            //     {
            //         method: 'GET', // *GET, POST, PUT, DELETE, etc.
            //         headers: {
            //             Accept: 'application/json',
            //             'Content-Type': 'application/json',
            //         },
            //         referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
            //         // body data type must match "Content-Type" header
            //     }
            // );
            //
            //
            // if (response.status === 200) {
            //     const releaseBody = await response.json();
            //     // const chatWidgeData = releaseBody.chatWidgeData || defaultWidgetData;
            //     const chatWidgeData = defaultWidgetData;
            //     //TODO:组件显示信息
            //     console.log(chatWidgeData);
            //     console.log(JSON.stringify(chatWidgeData))
            //     return {
            //         ...releaseBody,
            //         chatWidgeData: chatWidgeData
            //     }
            // } else {
            //     console.log('error');
            // }
            //return response;
            //TODO: 个人添加，考虑是否需要进一步修改
            const chatWidgeData = defaultWidgetData;
            const releaseBody = {};
            return {
                        ...releaseBody,
                        chatWidgeData: chatWidgeData
                    }
        }

        (async () => {
            const data = await getWidgetData();
            if(!knowledgebaseId) {
                knowledgebaseId = data.id;
            }
            const chatWidgetData = data.chatWidgeData;
            showReadMore = chatWidgetData.showReadMore;
            collectEmail = chatWidgetData.collectEmail;
            requestMetaData();

            const heading = document.getElementById('board-heading');
            const description = document.getElementById('board-desc');
            const offlineMsgHeading = document.getElementById('offline-msg-heading');
            const offlineMsgDescription = document.getElementById('offline-msg-desc');
            const branding = document.getElementById('powered-by');
            const buttonElement = document.getElementById("board-launcher-btn");
            const chatInputElement = document.getElementById("board-input");
            const offlineMsgNameLabel = document.getElementById("label-offline-msg-name");
            const offlineMsgEmailLabel = document.getElementById("label-offline-msg-email");
            const offlineMsgMessageLabel = document.getElementById("label-offline-msg-msg");
            const offlineMsgNameInput = document.getElementById("offline-msg-name");
            const offlineMsgEmailInput = document.getElementById("offline-msg-email");
            const offlineMsgMessageInput = document.getElementById("offline-msg-msg");
            const requiredFieldErrorMsg = document.querySelectorAll('.required-field');
            const invalidEmailErrorMsg = document.getElementById('invalid-feedback-email-invalid');
            const formSubmitSuccessMsg = document.getElementById("msg-success-text");
            const formSubmitErrorMsg = document.getElementById("msg-error-text");
            const formSendAgainBtn = document.getElementById("offline-msg-success-close");
            const formTryAgainBtn = document.getElementById("offline-msg-error-close");

            // TODO:ZZ launcher icon
            const defaultLauncherIcon = `<svg
                focusable="false"
                stroke="currentColor"
                fill="none"
                stroke-width="2"
                viewBox="0 0 24 24"
                stroke-linecap="round"
                stroke-linejoin="round"
                height="1em"
                width="1em"
                xmlns="http://www.w3.org/2000/svg"
                style=" width: 38px; height: 38px;">
                <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
                <path
                    d="M5.821 4.91c3.898 -2.765 9.469 -2.539 13.073 .536c3.667 3.127 4.168 8.238 1.152 11.897c-2.842 3.447 -7.965 4.583 -12.231 2.805l-.232 -.101l-4.375 .931l-.075 .013l-.11 .009l-.113 -.004l-.044 -.005l-.11 -.02l-.105 -.034l-.1 -.044l-.076 -.042l-.108 -.077l-.081 -.074l-.073 -.083l-.053 -.075l-.065 -.115l-.042 -.106l-.031 -.113l-.013 -.075l-.009 -.11l.004 -.113l.005 -.044l.02 -.11l.022 -.072l1.15 -3.451l-.022 -.036c-2.21 -3.747 -1.209 -8.392 2.411 -11.118l.23 -.168z"
                    stroke-width="0" fill="currentColor"></path>
            </svg>`

            const iconContainer = document.createElement("div");
            iconContainer.innerHTML = data?.launcherIcon?.svgElement || defaultLauncherIcon;
            buttonElement.appendChild(iconContainer);

            if (data.customKey || chatWidgetData.hideBranding || data.whitelabelling?.removeBranding) {
                branding.style.display = 'none';
            }

            if(chatWidgetData.offlineMsgTabHeader) {
                offlineMsgTab.innerText = chatWidgetData.offlineMsgTabHeader;
            }

            if(chatWidgetData.assistantTabHeader) {
                aiAssistantTab.innerText = chatWidgetData.assistantTabHeader;

                requestAnimationFrame(() => {
                    const width = aiAssistantTab.offsetWidth;
                    tabsActive.style.width = `${width - 5}px`;
                });
            }

            if (chatWidgetData.heading) {
                heading.innerText = chatWidgetData.heading;
            }
            if (chatWidgetData.description) {
                description.innerText = chatWidgetData.description;
            }

            if (chatWidgetData.chatInputPlaceholderText) {
                chatInputElement.placeholder = chatWidgetData.chatInputPlaceholderText;
            }

            let welcomeMessages = [];

            if (chatWidgetData.welcomeMessage) {
                welcomeMessages.push(chatWidgetData.welcomeMessage);
            } else {
                welcomeMessages = chatWidgetData.welcomeMessages || [defaultWelcomeMessage];
            }
            const welcomeMessagesHTML = welcomeMessages.map(msg => {
                return `<div class="chat-msg chatbot"><div class="chat-msg-text">${msg}</div></div>`
            }).join('');

            const chatMessages = document.getElementById('board-msg');
            chatMessages.insertAdjacentHTML("afterbegin", welcomeMessagesHTML)

            if (chatWidgetData.offlineMessage) {
                const chatWrap = document.getElementById('board-wrap');
                chatWrap.classList.add('has-offline-msg');
            }

            if(chatWidgetData.readMoreText) {
                readMoreText = chatWidgetData.readMoreText;
            }

            collectEmailText = chatWidgetData.collectEmailText || collectEmailText;

            if(chatWidgetData.offlineMsgHeading) {
                offlineMsgHeading.innerText = chatWidgetData.offlineMsgHeading;
            }

            if(chatWidgetData.offlineMsgDescription) {
                offlineMsgDescription.innerText = chatWidgetData.offlineMsgDescription;
            }

            if(chatWidgetData.nameFieldLabel) {
                offlineMsgNameLabel.innerText = chatWidgetData.nameFieldLabel;
            }

            if(chatWidgetData.emailFieldLabel) {
                offlineMsgEmailLabel.innerText = chatWidgetData.emailFieldLabel;
            }

            if(chatWidgetData.msgFieldLabel) {
                offlineMsgMessageLabel.innerText = chatWidgetData.msgFieldLabel;
            }

            if(chatWidgetData.nameFieldPlaceholder) {
                offlineMsgNameInput.placeholder = chatWidgetData.nameFieldPlaceholder;
            }

            if(chatWidgetData.emailFieldPlaceholder) {
                offlineMsgEmailInput.placeholder = chatWidgetData.emailFieldPlaceholder;
            }

            if(chatWidgetData.msgFieldPlaceholder) {
                offlineMsgMessageInput.placeholder = chatWidgetData.msgFieldPlaceholder;
            }

            if(chatWidgetData.requiredFieldMsg) {
                requiredFieldErrorMsg.forEach(div => {
                        div.innerText = chatWidgetData.requiredFieldMsg;
                });
            }

            if(chatWidgetData.invalidEmailMsg) {
                invalidEmailErrorMsg.innerText = chatWidgetData.invalidEmailMsg;
            }

            if(chatWidgetData.formSubmitBtnLabel) {
                offlineMessageBtn.innerText = chatWidgetData.formSubmitBtnLabel;
            }

            formSubmitBtnSubmittingText = chatWidgetData.formSubmitBtnSubmittingText ?? submitBtnSubmittingText;

            if (chatWidgetData.formSubmitSuccessMsg) {
                formSubmitSuccessMsg.innerText = chatWidgetData.formSubmitSuccessMsg;
            }

            if (chatWidgetData.formSubmitErrorMsg) {
                formSubmitErrorMsg.innerText = chatWidgetData.formSubmitErrorMsg;
            }

            if (chatWidgetData.formSendAgainBtnLabel) {
                formSendAgainBtn.innerText = chatWidgetData.formSendAgainBtnLabel;
            }

            if (chatWidgetData.formTryAgainBtnLabel) {
                formTryAgainBtn.innerText = chatWidgetData.formTryAgainBtnLabel;
            }

            var styleSheet = document.createElement('style');
            styleSheet.type = "text/css";

            const styles = `
                .chat-widget { border-radius: ${chatWidgetData.borderRadius}!important}
                .chat-header, .chat-loading-dot, .board-launcher-btn { background-color: ${chatWidgetData.backgroundColor}!important}
                .board-wrap {
                    opacity: 1 !important;
                }
                .board-launcher-btn {
                    color: ${chatWidgetData.fontColor}!important
                }
                .chat-header, .chat-tabs button, .btn-primary {color: ${chatWidgetData.fontColor}!important}
                .tabs-active, .btn-primary {background-color: ${chatWidgetData.backgroundColor}!important}
                .chat-submit-btn svg, .message-feedback, .lead-done-icon {
                    color: ${chatWidgetData.backgroundColor}!important
                }
                .chat-msg.user .chat-msg-text {background-color: ${chatWidgetData.backgroundColor}!important; color: ${chatWidgetData.fontColor}!important}
            `
            styleSheet.textContent = (chatWidgetData?.customCSS || '') + styles;


            if (chatWidgetData.questionExamples && chatWidgetData.questionExamples.length > 0) {
                const sampleMessages = document.getElementById('board-sample-msg');
                sampleMessages.classList.remove('hide-sample-msg');
                chatWidgetData.questionExamples.forEach((message) => {
                    const sampleMessage = document.createElement('div');
                    sampleMessage.classList.add('board-sample-msg');
                    sampleMessage.setAttribute('data-message', message.question);
                    sampleMessage.innerText = message.label;
                    sampleMessages.appendChild(sampleMessage);
                });
            }

            //TODO：关键步骤，入口，获取用户输入，发起请求
            document.getElementById('board-sample-msg').addEventListener('click', (e) => {
                if (e.target.classList.contains('board-sample-msg')) {
                    const message = e.target.getAttribute('data-message') || e.target.innerText;
                    // 发起请求
                    addMessageToChat(message);
                }
            });


            const widgetConfig = {}

            if (chatWidgetData.placement === 'left') {
                const chatLauncher = document.getElementById('board-launcher');
                chatLauncher.style.left = '20px';
                chatLauncher.style.right = 'auto';
                widgetConfig.position = 'left';
            }
            if(chatWidgetData.showAsPopup) {
                widgetConfig.showAsPopup = true;
                widgetConfig.popupDelay = chatWidgetData.popupDelay;
                widgetConfig.welcomeMessages = chatWidgetData.welcomeMessages;
            }
            notifyWidgetConfig(widgetConfig);

            setTimeout(() => {
                document.head.appendChild(styleSheet);
            }, 400);


        })();


        async function createSession(userData) {
            // TODO：url要以api开头才不会跨域
            //  response: 返回session id 字符串
            const response = await fetch(
                // `${baseURL}${'/chatbot/session?src=widget'}`,
                `${baseURL}${'/api/chat/session'}`,
                {
                    method: 'POST', // *GET, POST, PUT, DELETE, etc.
                    headers: {
                        Accept: 'application/json',
                        'Content-Type': 'application/json',
                    },
                    referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
                    // userData: {
                    //   userAgent: userAgent,
                    //     origin: origin
                    // }
                    body: JSON.stringify({
                        "knowledgebaseId": knowledgebaseId,
                        userData: userData
                    }), // body data type must match "Content-Type" header
                }
            );

            console.log(response)
            // console.log(response.text())

            if (response.status === 200) {
                const result = await response.text()
                return result;
            } else {
                console.log('error');
            }
            //return response;
        }

        async function updateSession(sessionId, userData) {
            const response = await fetch(
                `${baseURL}/chatbot/session/${sessionId}`,
                {
                    method: 'PUT', // *GET, POST, PUT, DELETE, etc.
                    headers: {
                        Accept: 'application/json',
                        'Content-Type': 'application/json',
                    },
                    referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
                    body: JSON.stringify({
                        userData: userData
                    }), // body data type must match "Content-Type" header
                }
            );
            if (response.status === 200) {
                const result = await response.text()
                return result;
            } else {
                console.log('error');
            }
            //return response;
        }

        //TODO：获取答案
        async function getAnswer(sessionId, query) {
            const response = await fetch(
                // `${baseURL}${'/chatbot/answer'}`,
                `${baseURL}${'/api/chat'}`,
                {
                    method: 'POST', // *GET, POST, PUT, DELETE, etc.
                    headers: {
                        Accept: 'application/json',
                        'Content-Type': 'application/json',
                    },
                    referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
                    body: JSON.stringify({
                        "knowledgebaseId": knowledgebaseId,
                        "sessionId": sessionId,
                        "query": query
                    }), // body data type must match "Content-Type" header
                }
            );

            if (response.status === 200) {
                const result = await response.text();
                console.log(result);
                return result;
            } else {
                console.log('error');

            }
            //return response;
            return '[ERR]';
        }






        // TODO:重要步骤，获取响应的函数
        // TODO:query对应message 是string
        // TODO:接口要直接返回字符串，而非json，通过event.data获取
        function getAnswerStream(sessionId, query, cb, errorCb) {
            //TODO:需要创建会话session，因为一个ChatBot可能有多个用户，所以需要session id
            // const url = `${baseURL}${'/chatbot/answer_stream'}?session=${sessionId}&query=${encodeURIComponent(query)}`;
            const url = `${baseURL}${'/api/chat'}?session=${sessionId}&query=${encodeURIComponent(query)}`;
            let source = new EventSource(url);

            source.onmessage = (e) => {
              console.log(e.data);
                cb(e.data);
                if (e.data == "[DONE]") {
                    source.close();
                }
            };

            source.onerror = (err) => {
                source.close();
                errorCb();
            };
        }


        async function addMessageToChat(message) {

            const input = document.getElementById('board-input');
            message = message || input.value.trim();
            if (!message) return;

            const newMessageUser = {
                role: "user",
                content: message
            };

            const chatMessages = document.getElementById('board-msg');
            chatMessages.insertAdjacentHTML("beforeend",
                `<div class="chat-msg user"><div class="chat-msg-text">${message}</div></div>`)

            const lastMesage = chatMessages.lastChild.querySelector('.chat-msg-text');
            chatMessages.scrollTop = chatMessages.scrollHeight;
            input.value = '';
            autosize.update(input);

            const userAgent = navigator.userAgent || navigator.vendor || window.opera;

            // TODO:流式传输
            if (STREAM_RESPONSE) {
                chatMessages.insertAdjacentHTML("beforeend",
                    `<div class="chat-msg chatbot"><div class="chat-msg-text"><div class='chat-loading-dot-cont'>
											<div class="chat-loading-dot"></div>
											<div class="chat-loading-dot"></div>
											<div class="chat-loading-dot"></div>
										</div></div></div>`)
                chatMessages.scrollTop = chatMessages.scrollHeight;
                const msgHolder = chatMessages.lastChild.querySelector('.chat-msg-text');
                let msg = '';
                if (!sessionId) {
                    sessionId = await createSession({
                        userAgent: userAgent,
                        origin: origin
                    });
                    notifyNewSession(sessionId);
                }

                //TODO:重要步骤，发起网络请求
                const response = getAnswerStream(sessionId, message, (data) => {

                    if (data !== "[DONE]") {
                        data = JSON.parse(data);
                        let content = data.content;
                        let sources = data.sources;
                        content = replaceAll(content, '<', '&lt;')
                        content = replaceAll(content, '>', '&gt;')
                        content = replaceAll(content, '\n', '<br/>')

                        let sourcesBtns = '';
                        if (showReadMore && sources && sources.length > 0) {

                            sources = sources.filter((p, i) => {
                                return i === sources.findIndex(q => q.url === p.url);
                            });

                            sourcesBtns = sources.map((source) => {
                                const parts = source.url.split('/');
                                const lastSegment = parts.pop() || parts.pop();
                                return `<a href="${source.url}" target="_blank" class="chat-source-btn">${lastSegment}</a>`
                            }).join('');
                            sourcesBtns = `<div class="chat-sources"><div class="chat-source-read-more">${readMoreText}</div>${sourcesBtns}</div>`
                        }

                        //data = data.replace(/\n/g, '<br/>')
                        msg = `${msg}${content}${sourcesBtns}`
                        // TOOD: print msg -> 流式传输不需要拼接，每次返回都是完整的，拼接过的
                        // -> As
                        // -> As a
                        // -> As a assistant
                        console.log(msg);
                        msgHolder.innerHTML = msg;
                    } else {
                        const newMessageAssistant = {
                            role: "assistant",
                            content: msg
                        };
                        //TODO:关键步骤，记录 OPENAI返回的聊天响应
                        messages.push(newMessageUser);
                        messages.push(newMessageAssistant);
                        notifyNewMessage(messages)
                        msg = replaceAll(msg, '&lt;', '<')
                        msg = replaceAll(msg, '&gt;', '>')
                        msg = replaceAll(msg, '<br/>', '\n')
                        const markdownRes = marked.parse(msg);
                        msgHolder.innerHTML = markdownRes;

                        // TODO：此处代码没有使用，collectEmail == false
                        if(collectEmail && isFirstMessage) {
                            const collectEmailMarkup = `<div class="chat-msg chatbot">
                                    <div
                                        class="chat-msg-text chat-msg-form"
                                        id="board-msg-form-email"
                                    >
                                        <div class="form-group">
                                            <label
                                                for="lead-email-input"
                                                >${collectEmailText}</label
                                            >
                                            <div id="lead-email-form" class="input-group">
                                                <input
                                                    type="text"
                                                    class="form-control"
                                                    id="lead-email-input"
                                                    placeholder="hi@example.com"
                                                />
                                                <button
                                                    class="chat-submit-btn"
                                                    id="lead-email-input-submit"
                                                    type="submit"
                                                >
                                                    <svg
                                                        width="16"
                                                        height="16"
                                                        fill="none"
                                                        xmlns="http://www.w3.org/2000/svg"
                                                    >
                                                        <path
                                                        fill-rule="evenodd"
                                                        clip-rule="evenodd"
                                                        d="M4.394 14.7L13.75 9.3c1-.577 1-2.02 0-2.598L4.394 1.299a1.5 1.5 0 00-2.25 1.3v3.438l4.059 1.088c.494.132.494.833 0 .966l-4.06 1.087v4.224a1.5 1.5 0 002.25 1.299z"
                                                        fill="currentColor"
                                                        ></path>
                                                    </svg>
                                                </button>
                                                <svg class="lead-done-icon" stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="18px" width="18px" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10 10-4.486 10-10S17.514 2 12 2zm-1.999 14.413-3.713-3.705L7.7 11.292l2.299 2.295 5.294-5.294 1.414 1.414-6.706 6.706z"></path></svg>
                                                <div class='chat-loading-dot-cont'>
                                                    <div class="chat-loading-dot"></div>
                                                    <div class="chat-loading-dot"></div>
                                                    <div class="chat-loading-dot"></div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>`;
                                chatMessages.insertAdjacentHTML("beforeend", collectEmailMarkup);
                                enableEmailCollection();
                                isFirstMessage = false;
                        }
                    }

                    chatMessages.scrollTop = chatMessages.scrollHeight;
                }, () => {
                    msgHolder.innerHTML = 'Oops! I am unable to answer right now!';
                });
            } else {
                chatMessages.insertAdjacentHTML("beforeend",
                  `<div class="chat-msg chatbot"><div class="chat-msg-text"><div class='chat-loading-dot-cont'>
                        <div class="chat-loading-dot"></div>
                        <div class="chat-loading-dot"></div>
                        <div class="chat-loading-dot"></div>
                      </div></div></div>`)
                // TODO: 自动滑动
                chatMessages.scrollTop = chatMessages.scrollHeight;
                const msgHolder = chatMessages.lastChild.querySelector('.chat-msg-text');

                // TODO:非流式传输
                if (!sessionId) {
                    sessionId = await createSession({
                        userAgent: userAgent
                    });
                    notifyNewSession(sessionId);
                }

                // TODO:根据session id获取答案
                const response = await getAnswer(sessionId, message);

                if(response != '[ERR]'){
                  const markdownRes = marked.parse(
                    response.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/, "")
                  )
                  // chatMessages.insertAdjacentHTML("beforeend",
                  //     `<div class="chat-msg chatbot"><div class="chat-msg-text">${markdownRes}</div></div>`);

                  // msgHolder.innerHTML = 'Oops! I am unable to answer right now!';
                  msgHolder.innerHTML = `<div class="chat-msg chatbot"><div class="chat-msg-text">${markdownRes}</div></div>`;

                  chatMessages.scrollTop = chatMessages.scrollHeight;
                }else{
                  msgHolder.innerHTML = 'Oops! I am unable to answer right now!';

                  chatMessages.scrollTop = chatMessages.scrollHeight;
                }

            }
        }

        async function saveEmail(email) {
            const input = document.getElementById('lead-email-input');
            email = email || input.value.trim();
            if (!email) return;
            const $emailFormCont = document.getElementById('board-msg-form-email');
            $emailFormCont.classList.add('board-msg-form-loading');
            const userAgent = navigator.userAgent || navigator.vendor || window.opera;
            try {
                await updateSession(sessionId, {
                    email: email,
                    userAgent: userAgent,
                    origin: origin
                });
            } catch (error) {
                console.log(error);
            } finally {
                $emailFormCont.classList.remove('board-msg-form-loading');
                $emailFormCont.classList.add('board-msg-form-submitted');
            }
        }

        function enableEmailCollection() {
            const leadInputForm = document.getElementById('lead-email-form');
            const emailInput = document.getElementById('lead-email-input');
            emailInput.addEventListener('keydown',  (e) => {
                if (e.keyCode === 13 || e.key === "Enter") {
                    e.preventDefault();
                    saveEmail();
                }
                const $emailFormCont = document.getElementById('board-msg-form-email');
                $emailFormCont.classList.remove('board-msg-form-submitted');
            });
            document.getElementById('lead-email-input-submit').addEventListener('click', (e)=>{
                e.preventDefault();
                saveEmail();
            })
        }


        // JavaScript code to handle the chat form submission
        const form = document.getElementById('board-form');

        form.addEventListener('submit', async (e) => {
            e.preventDefault();
            addMessageToChat();
        });

        document.getElementById('board-input').onkeydown = function (e) {
            if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.metaKey) {
                e.preventDefault();
                addMessageToChat();
            }
        };


        function notifyParentWidgetExpand() {
            window.top.postMessage('webwhiz:widget_expand', '*');
        }
        function notifyParentWidgetMaximize() {
            window.top.postMessage('webwhiz:widget_maximize', '*');
        }
        function notifyParentWidgetMinimize() {
            window.top.postMessage('webwhiz:widget_minimize', '*');
        }
        function notifyClearHistory() {
            window.top.postMessage('webwhiz:widget_clear_history', '*');
        }

        function notifyParentWidgetCollapse() {
            window.top.postMessage('webwhiz:widget_collapse', '*');
        }

        function notifyWidgetConfig(config) {
            window.top.postMessage({
                messageType: 'webwhiz:widget_config',
                config: config
            }, '*');
        }

        function notifyNewMessage(message) {
            window.top.postMessage({
                messageType: 'webwhiz:recieve_new_message',
                message: message
            }, '*');
        }
        function notifyNewSession(sessionId) {
            window.top.postMessage({
                messageType: 'webwhiz:recieve_new_session_id',
                sessionId: sessionId || ''
            }, '*');
        }

        function requestMetaData() {
            window.top.postMessage('webwhiz:request_meta_data', '*');
        }

        function requestChatHistoryData() {
            window.top.postMessage('webwhiz:request_chat_data', '*');
        }

        function requestSessionId() {
            window.top.postMessage('webwhiz:request_session_id', '*');
        }


        const offlineMessageBtn = document.getElementById('offline-msg-submit');

        if (offlineMessageBtn) {
            const $name = document.getElementById('offline-msg-name')
            const $email = document.getElementById('offline-msg-email')
            const $message = document.getElementById('offline-msg-msg')
            const $invlidEmail = document.getElementById('invalid-feedback-email');
            const $invlidEmailInvalid = document.getElementById('invalid-feedback-email-invalid');
            const $invlidName = document.getElementById('invalid-feedback-name')
            const $invlidMessage = document.getElementById('invalid-feedback-message')

            $name.addEventListener('blur', (e) => {
                if (e.target.value) {
                    $invlidName.classList.remove('feedback-visible')
                } else {
                    $invlidName.classList.add('feedback-visible')
                }
            })
            $email.addEventListener('blur', (e) => {
                if (e.target.value) {
                    const email = e.target.value;
                    const isValidEmail = validateEmail(email);
                    if (!isValidEmail) {
                        $invlidEmailInvalid.classList.add('feedback-visible');
                    } else {
                        $invlidEmailInvalid.classList.remove('feedback-visible');
                    }
                    $invlidEmail.classList.remove('feedback-visible');
                } else {
                    $invlidEmail.classList.add('feedback-visible');
                    $invlidEmailInvalid.classList.remove('feedback-visible');
                }
            })
            $message.addEventListener('blur', (e) => {
                if (e.target.value) {
                    $invlidMessage.classList.remove('feedback-visible')
                } else {
                    $invlidMessage.classList.add('feedback-visible')
                }
            })

            offlineMessageBtn.addEventListener('click', async (e) => {
                e.preventDefault();
                const name = $name.value;
                const email = $email.value;
                const message = $message.value;

                const userAgent = navigator.userAgent || navigator.vendor || window.opera;

                const isValidEmail = validateEmail(email);

                console.log(isValidEmail, name, message)

                if (isValidEmail && name && message) {

                    const prevBtnText = offlineMessageBtn.innerHTML;
                    offlineMessageBtn.innerHTML = formSubmitBtnSubmittingText;
                    offlineMessageBtn.setAttribute('disabled', true);
                    if (!sessionId) {
                        sessionId = await createSession({
                            userAgent: userAgent,
                            origin: origin
                        });
                        notifyNewSession(sessionId);
                    }

                    const response = await fetch(
                        `${baseURL}${'/offline_msg'}`,
                        {
                            method: 'POST', // *GET, POST, PUT, DELETE, etc.
                            mode: 'cors', // no-cors, *cors, same-origin
                            headers: {
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify({
                                "name": name,
                                "email": email,
                                "knowledgebaseId": knowledgebaseId,
                                "message": message,
                                "sessionId": sessionId,
                            }), // body data type must match "Content-Type" header
                        }
                    );

                    const $offlineMessage = document.getElementById('offline-msg');

                    if (response.status === 201) {
                        const result = await response.text()
                        $name.value = '';
                        $email.value = '';
                        $message.value = '';
                        $invlidEmail.classList.remove('feedback-visible');
                        $invlidName.classList.remove('feedback-visible');
                        $invlidEmailInvalid.classList.remove('feedback-visible');
                        $invlidMessage.classList.remove('feedback-visible');

                        $offlineMessage.classList.add('show-success-msg');
                    } else {
                        $offlineMessage.classList.add('show-error-msg');
                    }
                    offlineMessageBtn.innerHTML = prevBtnText;
                    offlineMessageBtn.removeAttribute('disabled');
                } else {
                    if (email && !isValidEmail) {
                        $invlidEmail.classList.remove('feedback-visible');
                        $invlidEmailInvalid.classList.add('feedback-visible');
                    }
                    if (!email) {
                        $invlidEmail.classList.add('feedback-visible');
                        $invlidEmailInvalid.classList.remove('feedback-visible');
                    }

                    if (email && isValidEmail) {
                        $invlidEmail.classList.remove('feedback-visible');
                        $invlidEmailInvalid.classList.remove('feedback-visible');
                    }

                    if (!name) {
                        $invlidName.classList.add('feedback-visible');
                    } else {
                        $invlidName.classList.remove('feedback-visible');
                    }
                    if (!message) {
                        $invlidMessage.classList.add('feedback-visible');
                    } else {
                        $invlidMessage.classList.remove('feedback-visible');
                    }
                }
            });

            const $offlineMessageClose = document.getElementById('offline-msg-success-close');
            const $offlineMessageErrorClose = document.getElementById('offline-msg-error-close');
            const $offlineMessage = document.getElementById('offline-msg');

            $offlineMessageClose.addEventListener('click', () => {
                $offlineMessage.classList.remove('show-success-msg');
            })
            $offlineMessageErrorClose.addEventListener('click', () => {
                $offlineMessage.classList.remove('show-error-msg');
            })

        }


        const aiAssistantTab = document.getElementById('tab-ai-assistant');
        const offlineMsgTab = document.getElementById('tab-offline-msg');
        const tabsActive = document.getElementById('tabs-active');

        const chatWrap = document.getElementById('board-wrap');

        if (offlineMsgTab) {
            offlineMsgTab.addEventListener('click', function () {
                const width = offlineMsgTab.offsetWidth;
                const left = aiAssistantTab.offsetWidth;
                tabsActive.style.width = `${width - 5}px`;
                tabsActive.style.left = `${left + 5}px`;
                chatWrap.classList.add('board-wrap-offline');
                chatWrap.classList.remove('board-wrap-ai-assistant');

            });
        }
        if (aiAssistantTab) {
            aiAssistantTab.addEventListener('click', function () {
                const width = aiAssistantTab.offsetWidth;
                tabsActive.style.width = `${width - 5}px`;
                tabsActive.style.left = `4px`;
                chatWrap.classList.add('board-wrap-ai-assistant');
                chatWrap.classList.remove('board-wrap-offline');
            });
        }
    </script>
</body>


</html>
